package io.unicorn.common.utils;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;

import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ExcelUtils {
    /**
     * @param response
     * @param fileName excel文件名
     * @param headMap 表头map
     * @param dataList 表格数据
     */
    public static void exportXlsx(
            HttpServletResponse response,
            String fileName,
            Map<String, String> headMap,
            List<Map<String, Object>> dataList
     ) {
 
        Workbook workbook = exportXlsx(fileName, headMap, dataList);
        response.setContentType("application/binary;charset=ISO8859_1");
 
        OutputStream outputStream = null;
 
        try {
            outputStream = response.getOutputStream();
            String fn = new String(fileName.getBytes(), "ISO8859_1");
            response.setHeader("Content-disposition", "attachment; filename=" + fn+"_"+ DateUtils.format(new Date(),"yyyyMMddHHmmss") + ".xlsx");
            workbook.write(outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                    } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } 
    }
 
    /**
     * 导出数据
     *
     * @param headMap
     * @param dataList
     */
    public static Workbook exportXlsx(
            String sheetName,
            Map<String, String> headMap,
            List<Map<String, Object>> dataList
    ) {

        Workbook workbook = new XSSFWorkbook(); 
        Sheet sheet = workbook.createSheet(sheetName); 
 
        int rowIndex = 0, columnIndex = 0;
        Set<String> keys = headMap.keySet();
 
        CellStyle style = workbook.createCellStyle();
        style.setBorderBottom(BorderStyle.THIN);//下边框
        style.setBorderLeft(BorderStyle.THIN);//左边框
        style.setBorderRight(BorderStyle.THIN);//右边框
        style.setBorderTop(BorderStyle.THIN); //上边框
        
        //表头
        Row row = sheet.createRow(rowIndex++);
        for (String key : keys) {
            Cell cell = row.createCell(columnIndex++);
            cell.setCellValue(headMap.get(key));
            cell.setCellStyle(style);
        }
 
        //内容
        if (dataList != null && !dataList.isEmpty()) {
            for (Map<String, Object> map : dataList) {
                row = sheet.createRow(rowIndex++);
                columnIndex = 0;
                for (String key : keys) {
                    Cell cell = row.createCell(columnIndex++);
                    setCellValue(cell, map.get(key));
                    cell.setCellStyle(style);
                }
            }
        }

        sheet.createFreezePane( 1, 1, 1, 1 );

        return workbook;
    }
 
    private static void setCellValue(Cell cell, Object obj) {
        if (obj == null) {
            return;
        }
        if (obj instanceof String) {
            cell.setCellValue((String) obj);
        } else if (obj instanceof Date) {
            Date date = (Date) obj;
            if (date != null) {
                cell.setCellValue(DateUtils.format(date));
            }
        } else if (obj instanceof Calendar) {
            Calendar calendar = (Calendar) obj;
            if (calendar != null) {
                cell.setCellValue(DateUtils.format(calendar.getTime()));
            }
        } else if (obj instanceof Timestamp) {
            Timestamp timestamp = (Timestamp) obj;
            if (timestamp != null) {
                cell.setCellValue(DateUtils.format(new Date(timestamp.getTime())));
            }
        } else if (obj instanceof Double) {
            cell.setCellValue((Double) obj);
        } else {
            cell.setCellValue(obj.toString());
        }
    }
    
    public static void exportXlsx(
    		HttpServletResponse response, 
    		String fileName,
    		String className,
            List<?> dataList)
    {    
    	try 
    	{
	    	Class<?> aClass = Class.forName(className);			
	    	
	    	Map<String, String> headNameMap = new LinkedHashMap<String, String>();

            try {
                //2022.1.2 如果有头映射函数就直接使用，发生异常则没有就维持原函数方法
                Method methodGetHeadMap = aClass.getDeclaredMethod("getHeadName");
                headNameMap = (Map<String, String>)methodGetHeadMap.invoke(null);

            }catch (Exception ex) {
                Field[] fields = aClass.getDeclaredFields();
                for (Field field : fields) {
                    if (!field.getName().equals("serialVersionUID")) {
                        headNameMap.put(field.getName(), field.getName());
                    }
                }
            }
	    	List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
	    	for(Object item : dataList) {
	    		Map<String, Object> map = new LinkedHashMap<String, Object>();
	    		   		
				try {
					Class<?> itemClass = item.getClass(); 
					Field[] itemFields = itemClass.getDeclaredFields();
	    		
					for (Field field  : itemFields){ 
						if (!field.getName().equals("serialVersionUID")) {
							Field declaredField = itemClass.getDeclaredField(field.getName());
							declaredField.setAccessible(true);
							PropertyDescriptor pd = new PropertyDescriptor(declaredField.getName(), itemClass);
							Method readMethod = pd.getReadMethod();
			    		
							map.put(field.getName(), readMethod.invoke(item));
						}
						
					}
				} catch (NoSuchFieldException e) {
			           e.printStackTrace();
			    } catch (IntrospectionException e) {
			            e.printStackTrace();
			    } catch (IllegalAccessException e) {
			          e.printStackTrace();
			    } catch (InvocationTargetException e) {
			            e.printStackTrace();
			    }
		        
	    		list.add(map);
	    	}
	    	
	    	ExcelUtils.exportXlsx(response, fileName, headNameMap, list);
	    	
    	} catch (ClassNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}//objEntity.class;
    }


    
}
